home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
010
/
blit.arc
/
BITBLT.C
< prev
next >
Wrap
Text File
|
1985-05-23
|
7KB
|
238 lines
/*
* name: bitblt
*
* description: copy the source rectangle r in a bitmap sb to the
* corresponding rectangle with origin p in the destination
* bitmap db using the optional halftone bitmap hb.
* (algorithm snarfed from the 1st smalltalk-80 book)
*
* synopsis: bitblt (sb, r, db, p, hb, f)
* struct bitmap *sb;
* struct rectangle *r;
* struct bitmap *db;
* struct point *p;
* struct bitmap *hb;
* int f;
*
* globals: rightmasks (r)
* allones (r)
*
* calls: merge (merge.c)
*
* called by: addobs (addobs.c)
* screenswap (screenswap.c)
* newlayer (newlayer.c)
* background (background.c)
* lbblt (lbblt.c)
* rectf (rectf.c)
*/
#include "layers.h"
unsigned short rightmasks[] = {
0x0000,
0x0003, 0x000f,
0x003f, 0x00ff,
0x03ff, 0x0fff,
0x3fff, 0xffff
};
unsigned short allones = 0xffff;
bitblt (sb, r, db, p, hb, f)
struct bitmap *sb; /* source bitmap */
struct rectangle *r; /* source rectangle */
struct bitmap *db; /* destination bitmap */
struct point *p; /* point in destination bitmap to start
operation */
struct bitmap *hb; /* halftone bitmap */
int f; /* operation to perform */
{
int sourceindex;
int destindex;
int sourcedelta;
int destdelta;
boolean preload;
int sx;
int sy;
int dx;
int dy;
int w;
int h;
int startpix;
int endpix;
int word;
int skew;
int nwords;
int vdir;
int hdir;
int i;
unsigned short merge ();
unsigned short t; /* temp for exchanging masks */
unsigned short prevword;
unsigned short thisword;
unsigned short skewword;
unsigned short mergemask;
unsigned short mergeword;
unsigned short destword;
unsigned short mask1;
unsigned short mask2;
unsigned short skewmask;
unsigned short halftoneword;
/*
* set w and h
*/
w = r -> corner.x - r -> origin.x;
h = r -> corner.y - r -> origin.y;
if ((w <= 0) || (h <= 0))
return; /* null range */
/*
* calculate sx, sy, dx and dy
*/
sx = r -> origin.x;
sy = r -> origin.y;
dx = p -> x;
dy = p -> y;
/*
* calculate skew and edge masks
*/
skew = (sx - dx) % pixels_word;
if (skew < 0)
skew += pixels_word;
/*
* how many bits source gets skewed to right
*/
startpix = pixels_word - (dx % pixels_word);
/*
* how many bits in first word
*/
mask1 = rightmasks[startpix];
endpix = pixels_word - ((dx + w - 1) % pixels_word + 1);
/*
* how many bits in last word
*/
mask2 = ~rightmasks[endpix];
skewmask = (skew == 0 ? 0 : rightmasks[pixels_word - skew]);
/*
* determine number of words stored per line
* merge masks if necessary
*/
if (w <= startpix) { /* i think this should be <=, not < */
mask1 = mask1 & mask2;
mask2 = 0;
nwords = 1;
}
else
nwords = ((w - startpix - 1) / pixels_word) + 2;
/*
* check for possible overlap of source and destination
*/
hdir = vdir = 1; /* default for no overlap */
if ((sb == db) && (dy >= sy)) {
if (dy > sy) { /* have to start at bottom */
vdir = -1;
sy = sy + h - 1;
dy = dy + h - 1;
}
else {
if (dx > sx) {
/*
* y's are equal, but x's are backwards
*/
hdir = -1;
sx = sx + w - 1;
/*
* start at right
*/
dx = dx + w - 1;
/*
* and fix up masks
*/
skewmask = ~skewmask;
t = mask1;
mask1 = mask2;
mask2 = t;
}
}
}
/*
* check if need to reload buffer (i.e., two words of
* source needed for first word of destination)
*/
preload = ((sb != null) && ((skew != 0) &&
((dx % pixels_word) <= (sx % pixels_word))));
if (hdir < 0)
preload = !preload;
/*
* calculate starting offsets
*/
if (sb != null)
sourceindex = (sy - sb -> bm_rect.origin.y) * sb -> bm_width +
(sx / pixels_word) -
(sb -> bm_rect.origin.x / pixels_word);
else
sourceindex = 0;
destindex = (dy - db -> bm_rect.origin.y) * db -> bm_width +
(dx / pixels_word) -
(db -> bm_rect.origin.x / pixels_word);
/*
* calculate increments from end of one line to start of next
*/
if (sb != null)
sourcedelta = (sb -> bm_width * vdir) - ((nwords + (preload ? 1 : 0)) * hdir);
else
sourcedelta = 0;
destdelta = (db -> bm_width * vdir) - (nwords * hdir);
/*
* perform the data transfer
*/
for (i = 1; i <= h; i++) { /* this is the vertical loop */
if (hb != null) {
halftoneword = *(hb -> bm_base + (dy % pixels_word));
dy = dy + vdir;
}
else
halftoneword = allones;
skewword = halftoneword;
if (preload) {
prevword = *(sb -> bm_base + sourceindex);
/*
* load the 16-bit shifter
*/
sourceindex = sourceindex + hdir;
}
else
prevword = 0;
mergemask = mask1;
/*
* here is the inner horizontal loop
*/
for (word = 1; word <= nwords; word++) {
if (sb != null) {
prevword = prevword & skewmask;
/*
* pick up next word
*/
thisword = *(sb -> bm_base + sourceindex);
skewword = prevword | (thisword & ~skewmask);
prevword = thisword;
/*
* 16-bit rotate (actually, this code will work on 32-bit ints as well)
*/
skewword = (skewword << skew) | (skewword >> (pixels_word - skew));
}
destword = *(db -> bm_base + destindex);
mergeword = merge ((skewword & halftoneword), destword, f);
*(db -> bm_base + destindex) = ((mergemask & mergeword) |
(~mergemask & destword));
sourceindex = sourceindex + hdir;
destindex = destindex + hdir;
if (word == (nwords - 1))
mergemask = mask2;
else
mergemask = allones;
}
sourceindex = sourceindex + sourcedelta;
destindex = destindex + destdelta;
}
}